/*
 * @(#)PermissionManager.java
 *
 * Copyright (c) 2003 DCIVision Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information of DCIVision
 * Ltd ("Confidential Information").  You shall not disclose such Confidential
 * Information and shall use it only in accordance with the terms of the license
 * agreement you entered into with DCIVision Ltd.
 */
package com.dcivision.framework;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.dbutils.DbUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.dcivision.alert.bean.UpdateAlert;
import com.dcivision.alert.bean.UpdateAlertType;
import com.dcivision.alert.dao.MtmUpdateAlertRecipientDAObject;
import com.dcivision.alert.dao.UpdateAlertDAObject;
import com.dcivision.alert.dao.UpdateAlertTypeDAObject;
import com.dcivision.dms.DmsOperationConstant;
import com.dcivision.dms.bean.DmsDocument;
import com.dcivision.dms.bean.DmsRoot;
import com.dcivision.dms.dao.DmsDocumentDAObject;
import com.dcivision.dms.dao.DmsPermissionDAObject;
import com.dcivision.dms.dao.DmsRootDAObject;
import com.dcivision.framework.bean.SysFunction;
import com.dcivision.user.bean.UserGroup;
import com.dcivision.user.bean.UserGroupPermission;
import com.dcivision.user.bean.UserPermissionInherit;
import com.dcivision.user.bean.UserRecord;
import com.dcivision.user.bean.UserRecordPermission;
import com.dcivision.user.bean.UserRole;
import com.dcivision.user.bean.UserRolePermission;
import com.dcivision.user.dao.MtmUserRecordUserGroupDAObject;
import com.dcivision.user.dao.MtmUserRecordUserRoleDAObject;
import com.dcivision.user.dao.UserGroupPermissionDAObject;
import com.dcivision.user.dao.UserPermissionInheritDAObject;
import com.dcivision.user.dao.UserRecordPermissionDAObject;
import com.dcivision.user.dao.UserRoleDAObject;
import com.dcivision.user.dao.UserRolePermissionDAObject;
import com.dcivision.workflow.bean.MtmWorkflowProgressSystemObject;
import com.dcivision.workflow.dao.MtmWorkflowProgressSystemObjectDAObject;
import com.dcivision.workflow.dao.WorkflowProgressDAObject;

/**
 * @author Administrator
 *
 */
public class PermissionManager {

  public static final String REVISION = "$Revision: 1.104.2.16 $";

  /** Indicates Deny Read Permission */
  public static final String DENIED_READ_PERMISSION = "r";
  
  /** Indicates Allow Read Permission */
  public static final String READ_PERMISSION = "R";
  
  /** Indicates Deny Execute permission */
  public static final String DENIED_EXECUTE_PERMISSION = "w";
  
  /** Indicates Allow Execute permission */
  public static final String EXECUTE_PERMISSION = "W";

  protected Log log = LogFactory.getLog(this.getClass().getName());

  private SessionContainer sessionContainer = null;
  private Hashtable hashFunctionPermission = new Hashtable();
  private ArrayList aMenuItem = null;
  private Integer[] accessibleFuncionList = null;

  private List userGroups = null;
  private List userRoles = null;
  private Integer[] userGroupIDs = null;
  private Integer[] userRoleIDs  = null;
  private Integer userRecordID=null;
  private boolean isCache=true;

  private Map permissionCache = new HashMap();
  
  //set for workflow user to provide all rights
  private final static String ALL_RIGHTS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

  // static variable
  private final static Hashtable hAdminFunction = new Hashtable();

  
  // listeners that has to been notified
  private static Hashtable sessionContainerListeners = new Hashtable();  
  
  // initialize the administrative system function
  static {
    hAdminFunction.put(SystemFunctionConstant.SETUP, "Y");
    hAdminFunction.put(SystemFunctionConstant.STAFF, "Y");
    hAdminFunction.put(SystemFunctionConstant.LOG, "Y");
  }

  public PermissionManager(SessionContainer sessionContainer) {
    this.sessionContainer = sessionContainer;
    this.userRecordID=sessionContainer.getUserRecordID();
  }

  public UserRecord getUserRecord() {
    return(this.sessionContainer.getUserRecord());
  }

  public Integer getUserRecordID() {
    return(this.sessionContainer.getUserRecordID());
  }

  public List getUserRoles() {
    return (this.userRoles);
  }

  public Integer[] getUserRoleIDs() {
    return (this.userRoleIDs);
  }

  public void setUserRoles(List userRoles) {
    this.userRoles = userRoles;
    if(userRoles!=null && userRoles.size()>0){
      userRoleIDs = new Integer[userRoles.size()];
      for(int i=0;i<userRoles.size();i++){
        userRoleIDs[i] = ((UserRole)userRoles.get(i)).getID();
      }
    }
  }

  public List getUserGroups() {
    return (this.userGroups);
  }

  public Integer[] getUserGroupIDs() {
    return (this.userGroupIDs);
  }

  public void setUserGroups(List userGroups) {
    this.userGroups = userGroups;
    if(userGroups!=null && userGroups.size()>0){
      userGroupIDs = new Integer[userGroups.size()];
      for(int i=0;i<userGroups.size();i++){
        userGroupIDs[i] = ((UserGroup)userGroups.get(i)).getID();
      }
    }
  }

  /**
   * get the accessible function list
   * @return the accessible function list
   */
  public Integer[] getAccessibleFuncionList() {
    return(this.accessibleFuncionList);
  }

  public List getMenuItem() {
    return (this.aMenuItem);
  }

 /**
   * true if the user record id under the current session equals the administrator id.
   * The administrator id is defined in the SYS_PARAMETER table.
   *
   * @return true if the current user is the administrator
   */
  public boolean isAdmin() {
    return(this.getUserRecordID() != null && this.getUserRecordID().toString().equals(SystemParameterFactory.getSystemParameter(SystemParameterConstant.ADMIN_ID)));
  }

  /**
   * hasAccessRight
   *
   * @param sFunctionCode  The function code
   * @param sRight         The access right. if equals to '*', it means match will any of the permission defined in the system.
   * @return               Whether the current login user has access right to
   *                       access that particular function.
   */
  public synchronized boolean hasAccessRight(String sFunctionCode, String sRight) {
    boolean bHasRight = false;

    if (this.hashFunctionPermission.isEmpty()) {
      this.initAccessibleSystemFunction();
    }
    String sFunctionPermission = (String) this.hashFunctionPermission.get(sFunctionCode);

    if (sFunctionPermission==null) { //don't have any permission
      bHasRight = false;
    } else { //have some permission in the function
      if (GlobalConstant.PERMISSION_ANY.equals(sRight)) { //check for have any permission
        bHasRight = true;
      } else { //check for specified permission
        bHasRight = (sFunctionPermission.indexOf(sRight) >= 0);
      }
    }

    //workflow user have all rights
    if (!this.sessionContainer.getByPassPermission()) {
      return (bHasRight);
    } 
    return true;
  }

  
  /**
   * hasAccessRight
   *
   * @param conn          Connection passed in   
   * @param sObjectType   The object type
   * @param nObjectID     The object ID
   * @param sRight        The access right which want to check
   * @return              Whether the current user has the given access right on a particularly object
   */  
  public synchronized boolean hasAccessRight(Connection conn, String sObjectType, Integer nObjectID, String sRight) throws ApplicationException {
    String permission = this.getPermission(conn, sObjectType, nObjectID);
    if (Utility.isEmpty(permission)) { 
      return false; 
      }
    return(permission.indexOf(sRight) >= 0);
  }  
  
  /**
   * hasAccessRight
   *
   * @param sObjectType   The object type
   * @param nObjectID     The object ID
   * @param sRight        The access right which want to check
   * @return              Whether the current user has the given access right on a particularly object
   */
  public synchronized boolean hasAccessRight(String sObjectType, Integer nObjectID, String sRight) throws ApplicationException {
    String permission = this.getPermission(sObjectType, nObjectID);
    if(Utility.isEmpty(permission)) {
      return false;
    } 
    return(permission.indexOf(sRight) >= 0);
  }
  
  public synchronized boolean hasAccessRightByUserRecordId(Integer nUserRecordID,String sObjectType, Integer nObjectID, String sRight) throws ApplicationException {
    if(nUserRecordID==null){throw new ApplicationException("userRecordId is null in hasAccessRightByUserRecordId() method!");}
    Connection conn=null;
    try {
      conn = DataSourceFactory.getConnection();
      this.userRecordID=nUserRecordID;
      this.isCache=false;
      MtmUserRecordUserRoleDAObject mtmUserRecordUserRoleDAObject = new MtmUserRecordUserRoleDAObject(this.sessionContainer,conn);
      MtmUserRecordUserGroupDAObject mtmUserRecordUserGroupDAObject = new MtmUserRecordUserGroupDAObject(this.sessionContainer, conn);
      this.setUserRoles(mtmUserRecordUserRoleDAObject.getUserRoleListByUserRecordID(userRecordID));
      this.setUserGroups(mtmUserRecordUserGroupDAObject.getUserGroupListByUserRecordID(userRecordID));
    } catch (Exception exp) {
      log.error(exp);
      throw new ApplicationException(exp);
    }finally {
      try {
        DbUtils.close(conn);
      } catch (SQLException exp) {
        log.error(exp);
      }
    }
    return this.hasAccessRight(sObjectType,nObjectID, sRight);
  }

  /**
   * isAccessible
   *
   * @param sObjectType   The object type
   * @param nObjectID     The object ID
   * @return              Whether the current user has the basic access right(READ) on a particular object
   */
  public synchronized boolean isAccessible(String sObjectType, Integer nObjectID) throws ApplicationException {
    if (!this.sessionContainer.getByPassPermission()) {

      if (sessionContainer.getUserRecordID()==null) {
        log.debug("session expired!!!!!!!!!!!!!!!!!!");
        throw new ApplicationException(ErrorConstant.LOGIN_SESSION_EXPIRED);
      }

      if (GlobalConstant.OBJECT_TYPE_FUNCTION.equals(sObjectType)) {
        String sFunctionCode = null;
        sFunctionCode = this.sessionContainer.getAppContainer().getSysFunctionByFunctionID(nObjectID).getFunctionCode();
        if (!hasAccessRight(sFunctionCode, "R")) {
          log.debug("unauthroized access!!!!!!!!!!!!!!!!!!");
          throw new ApplicationException(ErrorConstant.COMMON_UNAUTHORIZED_ACCESS);
        }
      } else if (GlobalConstant.OBJECT_TYPE_DOCUMENT.equals(sObjectType)) {
      }
    }
    return true;
  }

  /**
   * initAccessibleSystemFunction
   */
  public synchronized void initAccessibleSystemFunction() {
    ApplicationContainer appContainer = this.sessionContainer.getAppContainer();
    List allMenuItem = appContainer.getSysFunctionList();

    if (this.isAdmin()) {
      if (this.aMenuItem == null) {
        try{
          this.aMenuItem = new ArrayList();
          for (int i = 0; i < allMenuItem.size(); i++) {
            SysFunction tmpFunction = (SysFunction)allMenuItem.get(i);
            if (tmpFunction.getParentID().intValue() > 0) {
              try {
                SysFunction parentFunction = this.sessionContainer.getAppContainer().getSysFunctionByFunctionID(tmpFunction.getParentID());
                if (this.hAdminFunction.get(parentFunction.getFunctionCode().trim()) != null) {
                  this.aMenuItem.add(tmpFunction);
                  this.hashFunctionPermission.put(tmpFunction.getFunctionCode(), tmpFunction.getPermissionType());
                }
              } catch(Exception ignore){
                log.error(ignore, ignore);
              }
            } else if (this.hAdminFunction.get(tmpFunction.getFunctionCode().trim())!=null) {
              this.aMenuItem.add(tmpFunction);
            }
          }
        } catch (Exception ignore) {
          log.error(ignore, ignore);
        }
      }
    } else if (this.aMenuItem == null) {
      this.aMenuItem = new ArrayList();

      // Get the accessible function list.
      if (this.accessibleFuncionList == null) {
        Hashtable hashFuncID = null;
        try {
          hashFuncID = this.getAccessibleObjectHash(GlobalConstant.OBJECT_TYPE_FUNCTION);
          Map hashParentFuncID = new HashMap();
          Enumeration funcIDKeys = hashFuncID.keys();
          while (funcIDKeys.hasMoreElements()) {
            Integer functionID = (Integer) funcIDKeys.nextElement();
            SysFunction sysFunction = appContainer.getSysFunctionByFunctionID(functionID);
            if (sysFunction != null) {
              this.hashFunctionPermission.put(sysFunction.getFunctionCode(), hashFuncID.get(functionID));
              // Force to add a parent function to the list in order to show it in the menu.
              if (sysFunction.getParentID()!=null && sysFunction.getParentID().intValue()!=0 && (String)hashFuncID.get(functionID)!=null && ((String)hashFuncID.get(functionID)).indexOf(DENIED_READ_PERMISSION) < 0) {
                SysFunction parentFunction = appContainer.getSysFunctionByFunctionID(sysFunction.getParentID());
                hashParentFuncID.put(parentFunction.getID(), parentFunction.getPermissionType());
                this.hashFunctionPermission.put(parentFunction.getFunctionCode(), hashParentFuncID.get(parentFunction.getID()));
              }
            }
          }
          hashFuncID.putAll(hashParentFuncID);
        } catch (Exception e) {
          log.error(e, e);
        }
        java.util.Vector colAllFuncID = new java.util.Vector(hashFuncID.keySet());
        this.accessibleFuncionList = new Integer[colAllFuncID.size()];
        for (int i = 0; i < colAllFuncID.size(); i++) {
          this.accessibleFuncionList[i] = (Integer)colAllFuncID.get(i);
        }
      }

      if (this.accessibleFuncionList != null) {
        for (int j = 0; j < allMenuItem.size(); j++) {
          for (int i = 0; i < this.accessibleFuncionList.length; i++) {
            if (((com.dcivision.framework.bean.SysFunction)allMenuItem.get(j)).getID().equals(this.accessibleFuncionList[i])) {
              this.aMenuItem.add(allMenuItem.get(j));
            }
          }
        }
      }
    }
  }

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Just for temporary use in order to minimize modification on JSP, this function will be deleted.
  //////////////////////////////////////////////////////////////////////////////////////////////////
  public synchronized List getAccessibleObjectIDList(String objectType) throws ApplicationException {
    return this.getAccessibleObjectIDList((Connection)null, objectType);
  }

  public synchronized List getAccessibleObjectIDList(Connection dbConn, String objectType) throws ApplicationException {
    List aAccessibleObjectID = new ArrayList();
    Hashtable hAccessibleObject = this.getAccessibleObjectHash(dbConn, objectType);
    Set setObjectID = hAccessibleObject.keySet();
    for(Iterator iter=setObjectID.iterator(); iter.hasNext(); ) {
      Integer nObjectID = (Integer) iter.next();
      String sObjectPermission = (String) hAccessibleObject.get(nObjectID);
      // if contains "r" (case sensitive), read access is denied. Do not add it to the return id list
      if (sObjectPermission.indexOf(DENIED_READ_PERMISSION) < 0) {
        aAccessibleObjectID.add(nObjectID);
      }
    }
    return aAccessibleObjectID;
  }

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Just for temporary use in order to minimize modification on JSP, this function will be deleted.
  //////////////////////////////////////////////////////////////////////////////////////////////////
  public synchronized List getAccessibleObjectIDList(String objectType, String permissionType) throws ApplicationException {
    return this.getAccessibleObjectIDList((Connection)null, objectType, permissionType);
  }

  public synchronized List getAccessibleObjectIDList(Connection dbConn, String objectType, String permissionType) throws ApplicationException {
    List aAccessibleObjectID = new ArrayList();
    Hashtable hAccessibleObject = this.getAccessibleObjectHash(dbConn, objectType);
    Set setObjectID = hAccessibleObject.keySet();
    for(Iterator iter=setObjectID.iterator(); iter.hasNext(); ) {
      Integer nObjectID = (Integer) iter.next();
      String sObjectPermission = (String) hAccessibleObject.get(nObjectID);
      // if the permission string contain that "permissionType", then add it to the list.
      if (sObjectPermission.indexOf(permissionType) >= 0) {
        aAccessibleObjectID.add(nObjectID);
      }
    }
    return aAccessibleObjectID;
  }

  // Just for temporary use in order to minimize modification on JSP, this function will be deleted.
  public synchronized List getAccessibleObjectIDList(String objectType, Integer parentID) throws ApplicationException {
    return this.getAccessibleObjectIDList((Connection)null, objectType, parentID);
  }

  public synchronized List getAccessibleObjectIDList(Connection dbConn, String objectType, Integer parentID) throws ApplicationException {
    List aAccessibleObjectID = new ArrayList();
    Hashtable hAccessibleObject = this.getAccessibleObjectHash(dbConn, objectType, parentID);
    Set setObjectID = hAccessibleObject.keySet();
    for(Iterator iter=setObjectID.iterator(); iter.hasNext(); ) {
      Integer nObjectID = (Integer) iter.next();
      String sObjectPermission = (String) hAccessibleObject.get(nObjectID);
      // if contains "r" (case sensitive), read access is denied. Do not add it to the return id list
      if (sObjectPermission.indexOf(DENIED_READ_PERMISSION) < 0) {
        aAccessibleObjectID.add(nObjectID);
      }
    }
    return aAccessibleObjectID;
  }

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Just for temporary use in order to minimize modification on JSP, this function will be deleted.
  //////////////////////////////////////////////////////////////////////////////////////////////////
  public synchronized Hashtable getAccessibleObjectHash(String objectType) throws ApplicationException {
    return this.getAccessibleObjectHash((Connection)null, objectType);
  }

  public synchronized Hashtable getAccessibleObjectHash(Connection dbConn, String objectType) throws ApplicationException {
    return this.getAccessibleObjectHashByUserRecordID(dbConn, objectType, this.getUserRecordID());
  }

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Just for temporary use in order to minimize modification on JSP, this function will be deleted.
  //////////////////////////////////////////////////////////////////////////////////////////////////
  public synchronized Hashtable getAccessibleObjectHashByUserRecordID(String objectType, Integer userRecordID) throws ApplicationException {
    return this.getAccessibleObjectHashByUserRecordID((Connection)null, objectType, userRecordID);
  }

  public synchronized Hashtable getAccessibleObjectHashByUserRecordID(Connection dbConn, String objectType, Integer userRecordID) throws ApplicationException {
    Connection conn = null;
    Hashtable hAccessibleObject = new Hashtable();

    try {
      if (dbConn == null) {
        conn = DataSourceFactory.getConnection();
      } else {
        conn = dbConn;
      }
      List aUserRoles = this.getUserRoles();
      List aUserGroups = this.getUserGroups();
      Integer nUserRecordID = this.getUserRecordID();

      // Must query through database, since userRecordID is given, most probably it won't be the current login user.
      if (userRecordID != null && !userRecordID.equals(this.getUserRecordID())) {
        MtmUserRecordUserRoleDAObject mtmUserRecordUserRoleDAObject = new MtmUserRecordUserRoleDAObject(this.sessionContainer, conn);
        MtmUserRecordUserGroupDAObject mtmUserRecordUserGroupDAObject = new MtmUserRecordUserGroupDAObject(this.sessionContainer, conn);
        UserRoleDAObject userRoleDAO = new UserRoleDAObject(this.sessionContainer, conn);
        aUserRoles = mtmUserRecordUserRoleDAObject.getUserRoleListByUserRecordID(userRecordID);
        aUserGroups = mtmUserRecordUserGroupDAObject.getUserGroupListByUserRecordID(userRecordID);
        nUserRecordID = userRecordID;
        for (int i = 0; i < aUserGroups.size(); i++) {
          UserGroup tmpUserGroup = (UserGroup) aUserGroups.get(i);
          List userRolesByGroup = userRoleDAO.getListByUserGroupID(tmpUserGroup.getID());
          for (int j = 0; j < userRolesByGroup.size(); j++) {
            if (!aUserRoles.contains(userRolesByGroup.get(j))) {
              aUserRoles.add(userRolesByGroup.get(j));
            }
          }
        }
      }

      // User Role permission.
      if (aUserRoles != null) {
        UserRolePermissionDAObject userRolePermissionDAO = new UserRolePermissionDAObject(this.sessionContainer, conn);
        for (int i = 0; i < aUserRoles.size(); i++) {
          UserRole userRole = (UserRole) aUserRoles.get(i);
          List funcPerm = userRolePermissionDAO.getListByUserRoleIDObjectType(userRole.getID(), objectType);
          for (int j = 0; j < funcPerm.size(); j++) {
            UserRolePermission userRolePerm = (UserRolePermission) funcPerm.get(j);
            if (this.isMatchRequired(conn, objectType, userRolePerm.getObjectID())) {
              String oldPerm = (String) hAccessibleObject.get(userRolePerm.getObjectID());
              String newPerm = userRolePerm.getPermission();
              hAccessibleObject.put(userRolePerm.getObjectID(), this.combinePermission(oldPerm, newPerm));
            } else {
              hAccessibleObject.put(userRolePerm.getObjectID(), "r");
            }
          }
        }
      }

      // User Group permission.
      if (aUserGroups != null) {
        UserGroupPermissionDAObject userGroupPermissionDAO = new UserGroupPermissionDAObject(this.sessionContainer, conn);
        for (int i = 0; i < aUserGroups.size(); i++) {
          UserGroup userGroup = (UserGroup) aUserGroups.get(i);
          List funcPerm = userGroupPermissionDAO.getListByUserGroupIDObjectType(userGroup.getID(), objectType);
          for (int j = 0; j < funcPerm.size(); j++) {
            UserGroupPermission userGroupPerm = (UserGroupPermission) funcPerm.get(j);
            if (this.isMatchRequired(conn, objectType, userGroupPerm.getObjectID())) {
              String oldPerm = (String) hAccessibleObject.get(userGroupPerm.getObjectID());
              String newPerm = userGroupPerm.getPermission();
              hAccessibleObject.put(userGroupPerm.getObjectID(), this.combinePermission(oldPerm, newPerm));
            } else {
              hAccessibleObject.put(userGroupPerm.getObjectID(), "r");
            }
          }
        }
      }

      // User Record permission.
      UserRecordPermissionDAObject userRecordPermissionDAO = new UserRecordPermissionDAObject(this.sessionContainer, conn);
      List funcPerm = userRecordPermissionDAO.getListByUserRecordIDObjectType(nUserRecordID, objectType);
      if (funcPerm != null) {
        for (int j = 0; j < funcPerm.size(); j++) {
          UserRecordPermission userRecordPerm = (UserRecordPermission) funcPerm.get(j);
          if (this.isMatchRequired(conn, objectType, userRecordPerm.getObjectID())) {
            String oldPerm = (String) hAccessibleObject.get(userRecordPerm.getObjectID());
            String newPerm = userRecordPerm.getPermission();
            hAccessibleObject.put(userRecordPerm.getObjectID(), this.combinePermission(oldPerm, newPerm));
          } else {
            hAccessibleObject.put(userRecordPerm.getObjectID(), "r");
          }
        }
      }

      for (Enumeration accObjKeys = hAccessibleObject.keys(); accObjKeys.hasMoreElements();) {
        Object tmpStr = accObjKeys.nextElement();
        if (hAccessibleObject.get(tmpStr).toString().indexOf("r")>=0) {
          hAccessibleObject.remove(tmpStr);
        }
      }

      return hAccessibleObject;
    } catch (ApplicationException appEx) {
      throw appEx;
    } catch (Exception e) {
      log.error(e, e);
      throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
    } finally {
      if (dbConn == null) {
        try { conn.close(); } catch (Exception ignore) {} finally { conn = null; }
      } else {
        conn = null;
      }
    }
  }

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Just for temporary use in order to minimize modification on JSP, this function will be deleted.
  //////////////////////////////////////////////////////////////////////////////////////////////////
  public synchronized Hashtable getAccessibleObjectHash(String objectType, Integer parentID) throws ApplicationException {
    return this.getAccessibleObjectHash((Connection)null, objectType, parentID);
  }

  public synchronized Hashtable getAccessibleObjectHash(Connection dbConn, String objectType, Integer parentID) throws ApplicationException {
    Connection conn = null;
    Hashtable hAccessibleObject = new Hashtable();

    try {
      if (dbConn == null) {
        conn = DataSourceFactory.getConnection();
      } else {
        conn = dbConn;
      }
      List aUserRoles = this.getUserRoles();
      List aUserGroups = this.getUserGroups();

      // User Role permission.
      if (aUserRoles != null) {
        UserRolePermissionDAObject userRolePermissionDAO = new UserRolePermissionDAObject(this.sessionContainer, conn);
        for (int i = 0; i < aUserRoles.size(); i++) {
          UserRole userRole = (UserRole) aUserRoles.get(i);
          List funcPerm = userRolePermissionDAO.getListByUserRoleIDObjectTypeParentID(userRole.getID(), objectType, parentID);
          for (int j = 0; j < funcPerm.size(); j++) {
            UserRolePermission userRolePerm = (UserRolePermission) funcPerm.get(j);
            if (this.isMatchRequired(conn, objectType, userRolePerm.getObjectID())) {
              String oldPerm = (String) hAccessibleObject.get(userRolePerm.getObjectID());
              String newPerm = userRolePerm.getPermission();
              hAccessibleObject.put(userRolePerm.getObjectID(), this.combinePermission(oldPerm, newPerm));
            } else {
              hAccessibleObject.put(userRolePerm.getObjectID(), "r");
            }
          }
        }
      }

      // User Group permission.
      if (aUserGroups != null) {
        UserGroupPermissionDAObject userGroupPermissionDAO = new UserGroupPermissionDAObject(this.sessionContainer, conn);
        for (int i = 0; i < aUserGroups.size(); i++) {
          UserGroup userGroup = (UserGroup) aUserGroups.get(i);
          List funcPerm = userGroupPermissionDAO.getListByUserGroupIDObjectTypeParentID(userGroup.getID(), objectType, parentID);
          for (int j = 0; j < funcPerm.size(); j++) {
            UserGroupPermission userGroupPerm = (UserGroupPermission) funcPerm.get(j);
            if (this.isMatchRequired(conn, objectType, userGroupPerm.getObjectID())) {
              String oldPerm = (String) hAccessibleObject.get(userGroupPerm.getObjectID());
              String newPerm = userGroupPerm.getPermission();
              hAccessibleObject.put(userGroupPerm.getObjectID(), this.combinePermission(oldPerm, newPerm));
            } else {
              hAccessibleObject.put(userGroupPerm.getObjectID(), "r");
            }
          }
        }
      }

      // User Record permission.
      UserRecordPermissionDAObject userRecordPermissionDAO = new UserRecordPermissionDAObject(this.sessionContainer, conn);
      List funcPerm = userRecordPermissionDAO.getListByUserRecordIDObjectTypeParentID(this.getUserRecordID(), objectType, parentID);
      if (funcPerm != null) {
        for (int j = 0; j < funcPerm.size(); j++) {
          UserRecordPermission userRecordPerm = (UserRecordPermission) funcPerm.get(j);
          if (this.isMatchRequired(conn, objectType, userRecordPerm.getObjectID())) {
            String oldPerm = (String) hAccessibleObject.get(userRecordPerm.getObjectID());
            String newPerm = userRecordPerm.getPermission();
            hAccessibleObject.put(userRecordPerm.getObjectID(), this.combinePermission(oldPerm, newPerm));
          } else {
            hAccessibleObject.put(userRecordPerm.getObjectID(), "r");
          }
        }
      }

      for (Enumeration hAccObjKeys = hAccessibleObject.keys(); hAccObjKeys.hasMoreElements();) {
        Object tmpStr = hAccObjKeys.nextElement();
        if (hAccessibleObject.get(tmpStr).toString().indexOf("r")>=0) {
          hAccessibleObject.remove(tmpStr);
        }
      }

      return hAccessibleObject;
    } catch (ApplicationException appEx) {
      throw appEx;
    } catch (Exception e) {
      log.error(e, e);
      throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
    } finally {
      if (dbConn == null) {
        try { conn.close(); } catch (Exception ignore) {} finally { conn = null; }
      } else {
        conn = null;
      }
    }
  }

  //////////////////////////////////////////////////////////////////////////////////////////////////
  // Just for temporary use in order to minimize modification on JSP, this function will be deleted.
  //////////////////////////////////////////////////////////////////////////////////////////////////
  public synchronized String getPermission(String objectType, Integer objectID) throws ApplicationException {
    return this.getPermission((Connection)null, objectType, objectID);
  }
  
  /**
   * Filter document permission by unfinished workflow.
   *
   * @param dbConn        DBConnection
   * @param objectType    Object type bind with workflow
   * @param sRight        Object ID bind with workflow
   * @return              Permission string of document by unfinished workflow
   * @author              Bill
   */
  public synchronized String filterDocumentPermissionByWorkflow(Connection dbConn,String objectType,Integer objectID) throws ApplicationException{
	//Get document permission
    String documentPermission=this.getPermission(dbConn, objectType, objectID);
    
    MtmWorkflowProgressSystemObjectDAObject mtmWorkflowProgressSystemObjectDAO=new MtmWorkflowProgressSystemObjectDAObject(this.sessionContainer,dbConn);
    WorkflowProgressDAObject workflowProgressDAO=new WorkflowProgressDAObject(this.sessionContainer,dbConn);
    List systemObjectByWorkflowProgressList=mtmWorkflowProgressSystemObjectDAO.getListByBeanClassNameObjectID(DmsDocument.class.getName(), objectID);
    if(Utility.isEmpty(systemObjectByWorkflowProgressList)){
      return documentPermission;
    }
    //Determine whether a work has been completed
    MtmWorkflowProgressSystemObject systemObjectByWorkflowProgress=(MtmWorkflowProgressSystemObject)systemObjectByWorkflowProgressList.get(0);
    boolean isProgressComplete=workflowProgressDAO.checkProgressComplete(systemObjectByWorkflowProgress.getTrackID());
    
	if(GlobalConstant.OBJECT_TYPE_DOCUMENT.equals(objectType) && !isProgressComplete){
	  //Set document permission by unfinished workflow
	  documentPermission=GlobalConstant.PERMISSION_DOCUMENT_BY_UNFINISHED_WORKFLOW;
	}
	return documentPermission;
  }
  
  public synchronized String getPermission(Connection dbConn, String objectType, Integer objectID) throws ApplicationException {
    String result = ALL_RIGHTS;
    Connection conn = null;
    if( objectID == null ) { return ""; }
    
    if (!this.sessionContainer.getByPassPermission()) {
      try {
        if (dbConn == null) {
          conn = DataSourceFactory.getConnection();
        } else {
          conn = dbConn;
        }
        String permissionString = this.getPermissionString(conn, objectType, objectID);
        log.debug("Object Permission ("+objectType+","+objectID+"):" + permissionString);
        result= (TextUtility.noNull(permissionString));
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      } finally {
        if (dbConn == null) {
          try { conn.close(); } catch (Exception ignore) {} finally { conn = null; }
        } else {
          conn = null;
        }
      }
    }
      return result;
  }

 
  protected synchronized String getPermissionString(Connection conn, String objectType, Integer objectID) throws ApplicationException {
    String result = "";
    if(this.userRecordID==null) {this.userRecordID=this.sessionContainer.getUserRecordID();}
    if(this.sessionContainer.getByPassPermission()){
      return ALL_RIGHTS;
    }else if (isCache && this.permissionCache.get(objectType + objectID)!=null) {
      return((String)this.permissionCache.get(objectType + objectID));
    }else{
      try {
        if (!this.isMatchRequired(conn, objectType, objectID)) {
          result = PermissionManager.DENIED_READ_PERMISSION;
        }else {
          // User Role permission.
          if(userRoleIDs!=null && userRoleIDs.length>0){
            UserRolePermissionDAObject userRolePermissionDAO = new UserRolePermissionDAObject(this.sessionContainer, conn);
            List userRolePermissions = userRolePermissionDAO.getPermissionListByUserRoleIDObjectTypeObjectID(userRoleIDs, objectType, objectID);
            for(int i=0;i<userRolePermissions.size();i++){
              result = combinePermission(result, (String)userRolePermissions.get(i));
            }
          }

          // User Group permission.
          if(userGroupIDs!=null && userGroupIDs.length>0){
            UserGroupPermissionDAObject userGroupPermissionDAO = new UserGroupPermissionDAObject(this.sessionContainer, conn);
            List userGroupPermissions = userGroupPermissionDAO.getPermissionListByUserGroupIDsObjectTypeObjectID(userGroupIDs, objectType, objectID);
            for(int i=0;i<userGroupPermissions.size();i++){
              result = combinePermission(result, (String)userGroupPermissions.get(i));
            }
          }

          // User Record permission.
          UserRecordPermissionDAObject userRecordPermissionDAO = new UserRecordPermissionDAObject(this.sessionContainer, conn);
          String permission = userRecordPermissionDAO.getPermissionByUserRecordIDObjectTypeObjectID(this.userRecordID, objectType, objectID);
          if(!Utility.isEmpty(permission)){
            result = combinePermission(result, permission);
          }

          // Find parent permission for some object types.
          if (GlobalConstant.OBJECT_TYPE_DOCUMENT.equals(objectType)) {
            com.dcivision.dms.dao.DmsDocumentDAObject docDAO = new com.dcivision.dms.dao.DmsDocumentDAObject(this.sessionContainer, conn);
            com.dcivision.dms.bean.DmsDocument doc = (com.dcivision.dms.bean.DmsDocument)docDAO.getObjectByID(objectID);
            if(Utility.isEmpty(doc)){
            	return result;
            }
            boolean inheritFlag = true;
            UserPermissionInheritDAObject userPermInheritDAO = new UserPermissionInheritDAObject(this.sessionContainer, conn);
            UserPermissionInherit tmpUserPermissionInherit = (UserPermissionInherit)userPermInheritDAO.getObjectByObjectTypeObjectID(GlobalConstant.OBJECT_TYPE_DOCUMENT, doc.getID());
            if (tmpUserPermissionInherit == null) {
                  inheritFlag = true;
            } else {
                  inheritFlag = false;
            }
            if (inheritFlag && !Utility.isEmpty(doc.getParentID()) && doc.getParentID().intValue() != 0) {
                  result = combinePermission(result, this.getPermissionString(conn, objectType, doc.getParentID()));
            }
          }
        }
        
        //tc move this code to here. for most time,we did not assign personal folder
        if (GlobalConstant.OBJECT_TYPE_DOCUMENT.equals(objectType)) {
            // Check personal permission. EIP-1571 07/01/23 LEE ADD
            DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(this.sessionContainer, conn);
            DmsRootDAObject dmsRootDAO = new DmsRootDAObject(this.sessionContainer, conn);
            DmsRoot dmsRoot = (DmsRoot)dmsRootDAO.getObjectByIDIgnoreRecordStatus(((DmsDocument)dmsDocumentDAO.getObjectByID(objectID)).getRootID());
            if (dmsRoot!=null) {
              if(DmsRoot.PERSONAL_ROOT.equals(dmsRoot.getRootType()) && this.userRecordID.equals(dmsRoot.getOwnerID())) {
                // If personal root is open, append all rights. 
                String permission = this.getPersonalPermission();
                if (permission.indexOf("R")!=-1) {
                  permission = ALL_RIGHTS;
                }
                return permission;
              }else if(DmsRoot.PERSONAL_ROOT.equals(dmsRoot.getRootType()) && !this.userRecordID.equals(dmsRoot.getOwnerID())) {
                // Others' personal documents append no permission. 
                result = "";
              }else if(!DmsRoot.PERSONAL_ROOT.equals(dmsRoot.getRootType()) && this.userRecordID.equals(dmsRoot.getOwnerID())){
            	 //public folder/dms   	 //if public folder,when user is dms root 's owner,user must have access role 
            	  result = TextUtility.noNull(result);
                  if (result.indexOf(DmsOperationConstant.DMS_PERMISSION_ALLOW_ACCESS_CONTROL.toLowerCase())>=0) { //has denied permission
                	  result = result.replace(DmsOperationConstant.DMS_PERMISSION_ALLOW_ACCESS_CONTROL.toLowerCase().charAt(0), DmsOperationConstant.DMS_PERMISSION_ALLOW_ACCESS_CONTROL.toUpperCase().charAt(0));
                  } else if (result.indexOf(DmsOperationConstant.DMS_PERMISSION_ALLOW_ACCESS_CONTROL.toUpperCase())<0) { //did not assigned with permission
                	  result = result + DmsOperationConstant.DMS_PERMISSION_ALLOW_ACCESS_CONTROL;
                  }  
              }
            }
            
            if( result.indexOf("R") == -1 ) {
              boolean invited = false;
              UpdateAlertDAObject alertDAObject = new UpdateAlertDAObject(sessionContainer,conn);
              UpdateAlertTypeDAObject alertTypeDAObject = new UpdateAlertTypeDAObject(sessionContainer,conn);
              MtmUpdateAlertRecipientDAObject recipientDAObject = new MtmUpdateAlertRecipientDAObject(sessionContainer,conn);
              
              UpdateAlert updateAlert = (UpdateAlert)alertDAObject.getByObjectTypeObjectID(DmsDocument.DOCUMENT_TYPE, objectID);
              if( !Utility.isEmpty(updateAlert)) {
                List updateAlertTypes = alertTypeDAObject.getActiveUpdateAlertType(updateAlert.getID(), UpdateAlert.INVITE_ACTION);
                for( int i = 0 ; i < updateAlertTypes.size(); i ++ ) {
                  UpdateAlertType updateAlertType = (UpdateAlertType)updateAlertTypes.get(i);
                  List ids = recipientDAObject.getRecipientIDList(updateAlert.getID(), updateAlertType.getID(), UpdateAlert.USER_RECIPIENT, GlobalConstant.RECORD_STATUS_ACTIVE);
                  if( ids.contains(sessionContainer.getUserRecordID())) {
                    invited = true;
                    break;
                  }
                }
              }
              if( invited ) {
                result += "R";
              }
            }
          }      
        if(isCache && !Utility.isEmpty(result)){
          this.permissionCache.put(objectType + objectID, result);
        }
        return result;
      } catch (ApplicationException appEx) {
        throw appEx;
      } catch (Exception e) {
        log.error(e, e);
        throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
      }
    }
  }

  public static String combinePermission(String source, String target) {
    if (Utility.isEmpty(source) && Utility.isEmpty(target)) {
      return null;
    } else if (Utility.isEmpty(source)) {
      return target;
    } else if (Utility.isEmpty(target)) {
      return source;
    } else if (GlobalConstant.PERMISSION_ALL.equals(source)) {
      return source;
    } else if (GlobalConstant.PERMISSION_ALL.equals(target)) {
      return target;
    } else {
      String newPermission = source;
      for (int i=0; i<target.length(); i++) {
        String singlePerm = target.substring(i, i+1);
        boolean bDenyPermission = (source.indexOf(singlePerm.toLowerCase())>=0);
        if (source.toLowerCase().indexOf(singlePerm.toLowerCase())<0 && !bDenyPermission) { //new and non-denied access right
          newPermission += singlePerm;
        } else if (source.toLowerCase().indexOf(singlePerm.toLowerCase())>=0) { //replace the access right anyway, so that can add the denied right
          newPermission = newPermission.replace(singlePerm.toUpperCase().charAt(0), singlePerm.charAt(0));
        }
      }
      return newPermission;
    }
  }
  
  protected synchronized boolean isMatchRequired(Connection conn, String objectType, Integer objectID) throws ApplicationException {
    return(isMatchRequired(conn, objectType, objectID, this.getUserRecordID()));
  }

  protected synchronized boolean isMatchRequired(Connection conn, String objectType, Integer objectID, Integer userRecordID) throws ApplicationException {
    // What is the purpose of this method?
    // Current user must be the roles or groups that definition with the object?
    List aUserRoles = this.getUserRoles();
    List aUserGroups = this.getUserGroups();
    Integer nUserRecordID = this.sessionContainer.getUserRecordID();
    Hashtable hashRoles = new Hashtable();
    Hashtable hashGroups = new Hashtable();

    try {
      // Retrieve user roles and groups if userRecordID is given.
      if (userRecordID != null && !userRecordID.equals(this.getUserRecordID())) {
        MtmUserRecordUserRoleDAObject mtmUserRecordUserRoleDAObject = new MtmUserRecordUserRoleDAObject(this.sessionContainer, conn);
        MtmUserRecordUserGroupDAObject mtmUserRecordUserGroupDAObject = new MtmUserRecordUserGroupDAObject(this.sessionContainer, conn);
        UserRoleDAObject userRoleDAO = new UserRoleDAObject(this.sessionContainer, conn);
        aUserRoles = mtmUserRecordUserRoleDAObject.getUserRoleListByUserRecordID(userRecordID);
        aUserGroups = mtmUserRecordUserGroupDAObject.getUserGroupListByUserRecordID(userRecordID);
        nUserRecordID = userRecordID;
        for (int i = 0; i < aUserGroups.size(); i++) {
          UserGroup tmpUserGroup = (UserGroup) aUserGroups.get(i);
          List userRolesByGroup = userRoleDAO.getListByUserGroupID(tmpUserGroup.getID());
          for (int j = 0; j < userRolesByGroup.size(); j++) {
            if (!aUserRoles.contains(userRolesByGroup.get(j))) {
              aUserRoles.add(userRolesByGroup.get(j));
            }
          }
        }
      }

      // Put the user roles ID of that user into Hash table using role ID as key.
      if (!Utility.isEmpty(aUserRoles)) {
        for (int i = 0; i < aUserRoles.size(); i++) {
          UserRole userRole = (UserRole)aUserRoles.get(i);
          hashRoles.put(userRole.getID(), "Y");
        }
      }

      // Put the user group ID of that user into Hash table using group ID as key.
      if (!Utility.isEmpty(aUserGroups)) {
        for (int i = 0; i < aUserGroups.size(); i++) {
          UserGroup userGroup = (UserGroup)aUserGroups.get(i);
          hashGroups.put(userGroup.getID(), "Y");
        }
      }

      // Initialize permission DAOs.
      UserRolePermissionDAObject userRolePermissionDAO = new UserRolePermissionDAObject(this.sessionContainer, conn);
      UserGroupPermissionDAObject userGroupPermissionDAO = new UserGroupPermissionDAObject(this.sessionContainer, conn);
      UserRecordPermissionDAObject userRecordPermissionDAO = new UserRecordPermissionDAObject(this.sessionContainer, conn);

      // Check required role(s).
      List roleRequiredList = userRolePermissionDAO.getRequiredListByObjectTypeObjectID(objectType, objectID);
      if (!Utility.isEmpty(roleRequiredList)) {
        for (int i = 0; i < roleRequiredList.size(); i++) {
          if (hashRoles.get(((UserRolePermission)roleRequiredList.get(i)).getUserRoleID()) == null) {
            return(false);
          }
        }
      }

      // Check required group(s).
      List groupRequiredList = userGroupPermissionDAO.getRequiredListByObjectTypeObjectID(objectType, objectID);
      if (!Utility.isEmpty(groupRequiredList)) {
        for (int i = 0; i < groupRequiredList.size(); i++) {
          if (hashGroups.get(((UserGroupPermission)groupRequiredList.get(i)).getUserGroupID()) == null) {
            return(false);
          }
        }
      }

      // Check required user(s).
      List userRequiredList = userRecordPermissionDAO.getRequiredListByObjectTypeObjectID(objectType, objectID);
      if (!Utility.isEmpty(userRequiredList)) {
        for (int i = 0; i < userRequiredList.size(); i++) {
          if (!nUserRecordID.equals(((UserRecordPermission)userRequiredList.get(i)).getUserRecordID())) {
            return(false);
          }
        }
      }

      return(true);
    } catch (ApplicationException appEx) {
      throw appEx;
    } catch (Exception e) {
      throw new ApplicationException(ErrorConstant.COMMON_FATAL_ERROR, e);
    }
  }

  public void clearPermissionCache() {
    if (this.permissionCache != null) {
      this.permissionCache.clear();
    }
  }

  public void clearPermissionCache(String objectType, Integer objectID) {
    if (this.permissionCache != null) {
      this.permissionCache.remove(objectType + objectID);
    }
  }

  /**
   * for deal with personal permission .
   * @return
   */
  public String getPersonalPermission(){
    StringBuffer result=new StringBuffer();
    if(this.hasAccessRight(SystemFunctionConstant.DMS_PERSONAL_FOLDER,"R")){
      result.append("R");
    }
    if(this.hasAccessRight(SystemFunctionConstant.DMS_PERSONAL_FOLDER,"E")){
      result.append("E");
    }
    if(this.hasAccessRight(SystemFunctionConstant.DMS_PERSONAL_FOLDER,"I")){
      result.append("I");
    }
    if(this.hasAccessRight(SystemFunctionConstant.DMS_PERSONAL_FOLDER,"D")){
      result.append("D");
    }
    if(this.hasAccessRight(SystemFunctionConstant.DMS_PERSONAL_FOLDER,"C")){
      result.append("C");
    }
    return result.toString();
  }

  
  public void putPermissionIntoCache(String key, String value) {
    this.permissionCache.put(key, value);
  }
  
  public boolean containsPermissionKey(String key) {
    return this.permissionCache.containsKey(key);
  }
  
  public void putAllPermission(Map mPermission) {
    this.permissionCache.putAll(mPermission);
  }
  
  public boolean hasAccessRight(Connection conn, String objType, Integer objId, String rootType, Integer rootOwnerId, String right) throws ApplicationException {
    String permission = (String)this.permissionCache.get(objType+String.valueOf(objId));
    if (permission==null) {
      if (GlobalConstant.OBJECT_TYPE_DOCUMENT.equals(objType) && (rootType==null || rootOwnerId==null)) {
        DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(this.sessionContainer, conn);
        DmsRootDAObject dmsRootDAO = new DmsRootDAObject(this.sessionContainer, conn);
        DmsRoot dmsRoot = (DmsRoot)dmsRootDAO.getObjectByID(((DmsDocument)dmsDocumentDAO.getObjectByID(objId)).getRootID());
        rootType = dmsRoot.getRootType();
        rootOwnerId = dmsRoot.getOwnerID();
        dmsDocumentDAO = null;
        dmsRootDAO = null;
      }
      permission = this.getPermission(conn, objType, objId, rootType, rootOwnerId);
    }
    return(permission.indexOf(right) >= 0);
  }
  
  /**
   * lee add for bug 6001 in 06/08/09
   * @param conn
   * @param documentId
   * @return
   * @throws ApplicationException
   */
  public String getDocumentLinkPermission(Connection conn, Integer documentId) throws ApplicationException {
    String permission = this.getPermission(conn, GlobalConstant.OBJECT_TYPE_DOCUMENT, documentId, null, null);
    return permission;
  }
  
  
  public String getPermission(
      Connection conn, 
      String objectType,
      Integer objectId, 
      String rootType, 
      Integer rootOwnerId) throws ApplicationException {
    DmsPermissionDAObject dmsPermissionDAObject = new DmsPermissionDAObject(this.sessionContainer, conn);
    try {
      String permission = (String)this.permissionCache.get(objectType+objectId);
      if (permission==null) {
        if (GlobalConstant.OBJECT_TYPE_DOCUMENT.equals(objectType) && (rootType==null || rootOwnerId==null)) {
          DmsDocumentDAObject dmsDocumentDAO = new DmsDocumentDAObject(this.sessionContainer, conn);
          DmsRootDAObject dmsRootDAO = new DmsRootDAObject(this.sessionContainer, conn);
          //joan.xiong update code for bug EIP-282 by 2006/12/07
          //DmsRoot dmsRoot = (DmsRoot)dmsRootDAO.getObjectByID(((DmsDocument)dmsDocumentDAO.getObjectByID(objectId)).getRootID());
          DmsRoot dmsRoot = (DmsRoot)dmsRootDAO.getObjectByIDIgnoreRecordStatus(((DmsDocument)dmsDocumentDAO.getObjectByID(objectId)).getRootID());
          //joan.xiong update code end
          rootType = dmsRoot.getRootType();
          rootOwnerId = dmsRoot.getOwnerID();
          dmsDocumentDAO = null;
          dmsRootDAO = null;
        }
        Integer userRecordId = this.sessionContainer.getUserRecordID();
        if (this.sessionContainer.getByPassPermission()) {
          permission = ALL_RIGHTS;
        } else if(DmsRoot.PERSONAL_ROOT.equals(rootType) && userRecordId.equals(rootOwnerId)) {
          // If persional root is open, append all rights.
          permission = this.getPersonalPermission();
          if (permission.indexOf("R")!=-1) {
            permission = ALL_RIGHTS;
          }
        }else if (DmsRoot.PERSONAL_ROOT.equals(rootType) && !userRecordId.equals(rootOwnerId)) {
          // Others' persional documents append no permission. EIP-1571 07/01/23 LEE 
          permission = null;
        }else {
          // Other object types or dms public documents
          List noCacheIds = new ArrayList();
          noCacheIds.add(objectId);
          List lUserRoleIds = this.getUserRoleIds(this.getUserRoles());
          List lUserGroupIds = this.getUserGroupIds(this.getUserGroups());

          // step one: put forbidden permission to cache and reomve from list
          boolean isForbidden = dmsPermissionDAObject.isForbiddenPermissionWhichNotInMatchRequired(objectType, objectId, lUserRoleIds, lUserGroupIds, userRecordId);
          if (isForbidden) {
            permission = DENIED_READ_PERMISSION;
          }else {
            permission = dmsPermissionDAObject.getDirectPermission(objectType, objectId, lUserRoleIds, lUserGroupIds, userRecordId);
            if (GlobalConstant.OBJECT_TYPE_DOCUMENT.equals(objectType)) {
              boolean isInherit = dmsPermissionDAObject.isInheritPermission(objectType, objectId);
              if (isInherit) {
                Integer parentId = dmsPermissionDAObject.getDocumentParentId(objectId);
                if(!Utility.isEmpty(parentId) && parentId.intValue() > 0){
                  String inheritPermission = this.getPermission(conn, objectType, parentId, rootType, rootOwnerId);
                  permission = PermissionManager.combinePermission(permission, inheritPermission);
                }
              }
            }
          }
          // step three: if user is doc owner then append permission "S"
          if (userRecordId.equals(rootOwnerId)) {
            permission = this.forceToAddPermission(permission, "S");
          }
        }
        if (Utility.isEmpty(permission)) {
          permission = "";
        }
        this.permissionCache.put(objectType+""+objectId, permission);
      }
      return permission;
    }catch (Exception ex) {
      log.error(ex, ex);
      throw new ApplicationException(ex);
    }
  }
  
  public void appendPermissionCache(
      Connection conn, 
      Integer objectId, 
      String objectType,
      String rootType, 
      Integer rootOwnerId) throws ApplicationException {
    this.getPermission(conn, objectType, objectId, rootType, rootOwnerId);
  }
  
  public void appendPermissionCache(
      Connection conn, 
      List objectIds,
      String objectType, 
      String rootType, 
      Integer rootOwnerId) throws ApplicationException {
    DmsPermissionDAObject dmsPermissionDAObject = new DmsPermissionDAObject(this.sessionContainer, conn);
    List operationIds = new ArrayList(objectIds);
    try {
      
      // search and remove node ids from cache
      for (int i = (operationIds.size() - 1); i >= 0; i--) {
        if (this.permissionCache.containsKey(objectType + "" + operationIds.get(i))) {
          operationIds.remove(i);
        }
      }
      
      // if some nodes has no permission cache then add the permission from database
      if (operationIds.size() > 0) {
        Integer userRecordId = this.sessionContainer.getUserRecordID();
        if (this.sessionContainer.getByPassPermission()) {
          String permission = ALL_RIGHTS;
          for (int i=0; i<operationIds.size(); i++ ) {
            this.permissionCache.put(objectType+""+operationIds.get(i), permission);
          }
        }else if (DmsRoot.PERSONAL_ROOT.equals(rootType) && userRecordId.equals(rootOwnerId)) {
          // If persional root is open, append all rights.
          String permission = this.getPersonalPermission();
          if (permission.indexOf("R")!=-1) {
            permission = ALL_RIGHTS;
          }
          for (int i=0; i<operationIds.size(); i++ ) {
            this.permissionCache.put(objectType+""+operationIds.get(i), permission);
          }
        }else if (DmsRoot.PERSONAL_ROOT.equals(rootType) && !userRecordId.equals(rootOwnerId)) {
          // Others' persional documents append no permission. EIP-1571 07/01/23 LEE 
          String permission = "";
          for (int i=0; i<operationIds.size(); i++ ) {
            this.permissionCache.put(objectType+""+operationIds.get(i), permission);
          }
        }else {
          // Other object types or dms public documents
          Map mResultPermission = new HashMap();
          List noCacheIds = new ArrayList(operationIds);
          
          List lUserRoleIds = this.getUserRoleIds(this.getUserRoles());
          List lUserGroupIds = this.getUserGroupIds(this.getUserGroups());

          // step one: put forbidden permission to cache and reomve from list
          Map mForbidPermission = dmsPermissionDAObject.getForbiddenPermissionMapWhichNotInMatchRequired(objectType, operationIds, lUserRoleIds, lUserGroupIds, userRecordId);
          if (mForbidPermission.size() > 0) {
            Iterator iterator = mForbidPermission.keySet().iterator();
            while (iterator.hasNext()) {
              operationIds.remove(new Integer(((String) iterator.next()).substring(1)));
            }
            mResultPermission.putAll(mForbidPermission);
          }

          // step two: get setting permission from database(if inherit is true
          // then combine the permission with parent's)
          if (operationIds.size() > 0) {
            Map mPermission = dmsPermissionDAObject.getDirectPermissionMap(objectType, operationIds, lUserRoleIds, lUserGroupIds, userRecordId);
            if (GlobalConstant.OBJECT_TYPE_DOCUMENT.equals(objectType)) {
              List notInheritPermissionObjectIds = dmsPermissionDAObject.getNotInheritPermissionObjectIds(objectType, operationIds);
              Map documentIdPidMap = dmsPermissionDAObject.getDocumentIdPidMap(operationIds);
              for (int i = 0; i < operationIds.size(); i++) {
                Integer objectId = (Integer) operationIds.get(i);
                Integer parentId = (Integer) documentIdPidMap.get(objectId);
                String permission = (String) mPermission.get(objectType + "" + objectId);
                if (parentId.intValue() > 0 && !notInheritPermissionObjectIds.contains(objectId)) {
                  String inheritPermission = this.getPermission(conn, objectType, parentId, rootType, rootOwnerId);
                  permission = PermissionManager.combinePermission(permission, inheritPermission);
                }
                mPermission.put(objectType + "" + objectId, permission != null ? permission : "");
              }
            }
            mResultPermission.putAll(mPermission);
          }
          // step three: if user is doc owner then append permission "S"
          if (userRecordId.equals(rootOwnerId)) {
            for (int i = 0; i < noCacheIds.size(); i++) {
              Integer objectId = (Integer) noCacheIds.get(i);
              String permission = (String) mResultPermission.get(objectType + "" + objectId);
              mResultPermission.put(objectType + "" + objectId, this.forceToAddPermission(permission, "S"));
            }
          }

          this.permissionCache.putAll(mResultPermission);
        }
      }
    }catch (Exception ex) {
      log.error(ex, ex);
      throw new ApplicationException(ex);
    }
  }
  
  private List getUserRoleIds(List userRoles) throws Exception {
    List userRoleIds = new ArrayList();
    for (int i=0; i<userRoles.size(); i++) {
      UserRole userRole = (UserRole)userRoles.get(i);
      userRoleIds.add(userRole.getID());
    }
    return userRoleIds;
  }
  
  private List getUserGroupIds(List userGroups) throws Exception {
    List userGroupIds = new ArrayList();
    for (int i=0; i<userGroups.size(); i++) {
      UserGroup userGroup = (UserGroup)userGroups.get(i);
      userGroupIds.add(userGroup.getID());
    }
    return userGroupIds;
  }
  
  private String forceToAddPermission(String permission, String accessType) throws Exception {
    accessType = accessType.toUpperCase();
    if (permission.indexOf(accessType)!=-1) {
      permission.replace(accessType.toLowerCase().charAt(0), accessType.charAt(0));
    }else {
      permission += accessType;
    }
    return permission;
  } 

  public static void addPermissionListener(SessionContainer sessionContainer){
    sessionContainerListeners.put(sessionContainer.getSessionID(),sessionContainer);
  }
  
  public static void removePermissionListener(SessionContainer sessionContainer){
    sessionContainerListeners.remove(sessionContainer.getSessionID());
  }

  /**
   * Beyond add for bug EIP-234
   * Update all user's sessionContainer permission cache by object type,object id
   * @param objectType 
   * @param objectID
   * @return
   */  
  public static void firePermissionChanged(String objectType, Integer objectID){
    // loop the listeners
    Hashtable listenersTable = sessionContainerListeners;    
    Enumeration en = listenersTable.elements();
    while(en.hasMoreElements()){      
      SessionContainer sessionContainer = (SessionContainer)en.nextElement();
      // clear permission string by object type,object id
      sessionContainer.getPermissionManager().clearPermissionCache(objectType,objectID);
    }
  }
  /**
   * Beyond add for bug EIP-234
   * Update all logined user's sessionContainer sysfunction cache  
   * @return 
   */  
  public static void fireSystemFunctionPermissionChanged(){
    // loop the listeners
    Hashtable listenersTable = sessionContainerListeners;    
    Enumeration en = listenersTable.elements();
    while(en.hasMoreElements()){      
      SessionContainer sessionContainer = (SessionContainer)en.nextElement();
      // clear function code permission string       
      sessionContainer.getPermissionManager().aMenuItem = null;
      sessionContainer.getPermissionManager().hashFunctionPermission.clear();
      sessionContainer.getPermissionManager().accessibleFuncionList = null;
    }
  }  
  
  /**
   * Static common method verify given permissionValue whether contains read permisson symbol.
   * 
   * @return true if given permission value contains read permission symbol, otherwise, return false.
   */
  public static boolean isContainsReadPermission(String permissionValue) {
    if (permissionValue == null) {
      throw new IllegalArgumentException("permissionValue cannot be null!");
    }
    
    return (permissionValue.indexOf(READ_PERMISSION) >= 0 ? true : false);
  }
}